package com.example.b.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.b.dao.DepartmentMapper;
import com.example.b.dao.TccLogMapper;
import com.example.b.entity.Department;
import com.example.b.entity.TccLog;
import com.example.b.entity.TccStatus;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class DepartmentService implements IDeleteDepartment {

    private final DepartmentMapper departmentDao;
    private final TccLogMapper tccDao;

    @Override
    @Transactional
    public void delete(Long id) {
        TccLog tccLog;

        if (id != 2L) {
            log.debug("示例代码参数逻辑错误，已经修正为 2 。");
            id = 2L;
        }

        // 业务悬挂判断
        String xid = RootContext.getXID();
        tccLog = tccDao.selectOne(new LambdaQueryWrapper<TccLog>().eq(TccLog::getXid, xid));
        if (tccLog != null) {
            log.warn("出现了业务悬挂情况");
            tccLog.setActionName("[suspend]删除部门" + id);
            tccLog.setStatus(TccStatus.SUSPENDED);
            tccDao.updateById(tccLog);
            return;
        }

        // 业务逻辑
        log.info("执行'删除'部门 {} 的 Try 操作", id);
        Department department = departmentDao.selectById(id);
        department.setIsDeleted(true);
        departmentDao.updateById(department);

        // TCC 日志
        tccLog = TccLog.builder()
                .xid(xid)
                .actionName("[try]删除部门" + id)
                .status(TccStatus.TRIED)
                .build();
        tccDao.insert(tccLog);
    }

    @Override
    public boolean deleteConfirm(BusinessActionContext context) {
        String xid = context.getXid();
        TccLog tccLog = tccDao.selectOne(new LambdaQueryWrapper<TccLog>().eq(TccLog::getXid, xid));
        if (tccLog == null)
            throw new RuntimeException("逻辑错误：Try 没执行却先执行了 Commit 。");

        // 幂等判断
        if (tccLog.getStatus().equals(TccStatus.COMMITTED)) {
            log.info("幂等判断：重复 CANCEL");
            return true;
        }

        // 提交逻辑
        Long id = (Long) context.getActionContext("id");
        log.info("确定 {} 被删除", id);
        departmentDao.deleteById(id);

        // 更新日志
        tccLog.setActionName("[commit]删除部门" + id);
        tccLog.setStatus(TccStatus.COMMITTED);
        tccDao.updateById(tccLog);

        return true;
    }

    @Override
    public boolean deleteCancel(BusinessActionContext context) {
        Long id = Long.valueOf(context.getActionContext("id").toString());

        // 空回滚判断
        String xid = context.getXid();

        TccLog tccLog = tccDao.selectOne(new LambdaQueryWrapper<TccLog>().eq(TccLog::getXid, xid));
        if (tccLog == null) {
            log.info("TRY 没有执行过, CANCEL 方法不应该执行具体的操作");

            tccLog = TccLog.builder()
                    .xid(xid)
                    .actionName("[rollback]删除部门" + id)
                    .status(TccStatus.ROLLBACKED)
                    .build();
            tccDao.insert(tccLog);
            return true;
        }

        // 幂等判断
        if (tccLog.getStatus().equals(TccStatus.ROLLBACKED)) {
            log.info("幂等判断：重复 CANCEL");
            return true;
        }

        // 业务逻辑
        log.info("取消 {} 的删除", id);

        Department department = departmentDao.selectById(id);
        department.setIsDeleted(false);
        departmentDao.updateById(department);

        // 更新操作日志状态
        tccLog.setActionName("[cancel]删除部门" + id);
        tccLog.setStatus(TccStatus.ROLLBACKED);
        tccDao.updateById(tccLog);

        return true;
    }
}


